package com.xy.novelmanagement.service.impl;

import com.alibaba.fastjson.JSON;
import com.xy.model.Catalog;
import com.xy.model.CatalogContent;
import com.xy.model.Novel;
import com.xy.novelmanagement.service.IBQGSpider;
import com.xy.novelmanagement.service.INovelAddService;
import com.xy.novelmanagement.websocket.BQGSocket;
import com.xy.utils.FileTypeUtil;
import com.xy.utils.JedisUtil;
import com.xy.utils.PropertiesUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.util.Streams;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import redis.clients.jedis.Jedis;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
@Slf4j
public class BQGSpiderImpl implements IBQGSpider {
    private Map<String, WebSocketSession> sessionMap;
    private String novelType;
    @Autowired
    private INovelAddService novelAddService;

    public WebDriver initWebDriver() throws Exception{
        ChromeOptions options = new ChromeOptions();
        // 设置允许弹框
        options.addArguments("disable-infobars", "disable-web-security");
        String driverPath = ResourceUtils.getURL("classpath:").getPath()+File.separator+"static"+File.separator+"driver"+File.separator+"chromedriver.exe";
        System.setProperty("webdriver.chrome.driver", driverPath);
        // 设置无gui 开发时还是不要加，可以看到浏览器效果
        options.addArguments("--headless");
        //设置代理
//				String ip = "112.111.217.76:9999";
//				options.addArguments("--proxy-server=http://" + ip);
        //开启webDriver进程
        WebDriver webDriver = new ChromeDriver(options);
        return webDriver;
    }

    @Override
    public void spiderNovel(String type, String num,String userId) {
        try {
            sessionMap = BQGSocket.getUserIdSessionMap();
            WebSocketSession session = sessionMap.get(userId);
            Map<String, String> novelURLMap = new HashMap<>();
            log.info("session=" + session);
            if (session != null) {
                //开始爬小说及发送结果给浏览器
                String baseURL = "https://www.ibiqiuge.com/";
                String typeURL = "";
                //开启webDriver进程
                WebDriver webDriver = initWebDriver();
                webDriver.get(baseURL);
                String currentUrl = webDriver.getCurrentUrl();
                session.sendMessage(new TextMessage(currentUrl));
                List<WebElement> aList = webDriver.findElements(By.xpath("/html/body/nav/a"));

                for (WebElement element : aList) {
                    String text = element.getText();
                    //log.info("xpath" + text);
                    session.sendMessage(new TextMessage(text));
                    //【匹配网站分类】
                    if (text.equals(type)) {
                        typeURL = baseURL + element.getAttribute("href").replace(baseURL, "");
                        element.click();
                        this.novelType = text;
                        break;
                    }
                }
                Thread.sleep(1000);
                //考虑翻页情况
                int pageSize = webDriver.findElements(By.cssSelector("body > div.container.flex.flex-wrap.section-bottom.mb20 > div.border3-1.lastupdate > div.list-out > span.flex.w80 > em:nth-child(2) > a")).size();
                int page = Integer.parseInt(num) / pageSize + 1;
                for (int n = 0; n < page; n++) {
                    //如果不是第一页则点击下一页
                    if (n != 0) {
                        webDriver.findElement(By.xpath("//*[@id=\"pagelink\"]/a[12]")).click();
                        Thread.sleep(1000);
                    }
                    aList = webDriver.findElements(By.cssSelector("body > div.container.flex.flex-wrap.section-bottom.mb20 > div.border3-1.lastupdate > div.list-out > span.flex.w80 > em:nth-child(2) > a"));//小说链接
                    int bookNum = Math.min((Integer.parseInt(num) - n * pageSize), pageSize);
                    for (int i = 0; i < bookNum; i++) {
                        WebElement e = aList.get(i);
                        String href = e.getAttribute("href");
                        String text = e.getText();
                        session.sendMessage(new TextMessage("小说：" + text + " href:" + href));
                        novelURLMap.put(i + "", text + "|" + href);
                    }
                }
                for (int n = 0; n < novelURLMap.size(); n++) {
                    String val = novelURLMap.get(n + "");
                    String text = val.split("\\|")[0];
                    String url = val.split("\\|")[1];
                    session.sendMessage(new TextMessage("开始爬小说：《" + text + "》"));

                    if (saveNovel(webDriver, session, url, text)) {
                        session.sendMessage(new TextMessage(">>>>>爬小说：《" + text + "》 成功！"));
                    } else {
                        session.sendMessage(new TextMessage("<<<<<爬小说：《" + text + "》 失败！"));
                    }
                }
                webDriver.close();
                webDriver.quit();
                log.info("session is open {}",session.isOpen());
                if(session.isOpen()){
                    session.close();
                }
            }
            sessionMap.remove(userId);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Boolean saveNovel(WebDriver webDriver, WebSocketSession session, String url, String bookName) {
        boolean flag = true;
        List<Catalog> catalogList = new ArrayList<>();
        List<CatalogContent> catalogContentList = new ArrayList<>();
        Jedis jedis = JedisUtil.getConnect();
        String KEY = "Slist";
        Novel bookMsg = novelAddService.getNovelByName(bookName);
		Integer bookWords = bookMsg==null?0:bookMsg.getBookWords();
		try {
            if (!jedis.exists(KEY)) {
                jedis.hset(KEY, "count", 0 + "");//当对象不存在时创建
            }
            if (jedis.hexists(KEY, bookName)) {//如果小说以经爬过，则从上次爬取的章节继续
                webDriver.get(url);
                Thread.sleep(1000);
                //》》》获取章节信息开始《《《
                boolean isNotNew = true;
                int catalogNUM = webDriver.findElements(By.cssSelector("body > div.container.border3-2.mt8.mb20 > div.info-chapters.flex.flex-wrap > a")).size();
                for (int i = 0; i < catalogNUM; i++) {
                    WebElement e = webDriver.findElements(By.cssSelector("body > div.container.border3-2.mt8.mb20 > div.info-chapters.flex.flex-wrap > a")).get(i);
                    String text = e.getText();//章节名

                    StringBuffer catalogContent = new StringBuffer("");
                    log.info("章节名：" + text);
                    if (isNotNew) {//如果不是最新章节或小说还未获取章节
                        isNotNew = !(text.equals(jedis.hget(KEY, bookName)) || "".equals(jedis.hget(KEY, bookName)));
                        continue;
                    }
                    e.click();//跳转到章节内容页面<<<<<<<<<<
                    Thread.sleep(1000);
                    Catalog catalog = new Catalog();//新建章节对象
                    catalog.setNovelName(bookName);
                    catalog.setNovelCatalog(text);
                    catalog.setVip(0);
                    catalog.setUpdateTime(new Date());
                    while (true) {
                        try {
                            WebElement element = webDriver.findElement(By.cssSelector("#article"));
                            catalogContent.append(element.getText());
                            WebElement nextPage = webDriver.findElement(By.cssSelector("div.reader-main > div.read_nav > a#next_url"));
//                            log.info("nextPage=" + nextPage.getText());
                            if (nextPage.getText().equals("下一页")) {
                                nextPage.click();
                                log.info("下一页URL：" + webDriver.getCurrentUrl());
                                Thread.sleep(1000);
                            } else {
                                break;
                            }
                        } catch (InterruptedException interruptedException) {
                            log.error("定位元素失败");
                        }
                    }
                    log.info("章节内容：" + catalogContent.toString().substring(0, 10));
                    bookWords+=catalogContent.length();//更新数据库小说字数
                    novelAddService.updateWords(bookWords,bookName);
                    CatalogContent content = new CatalogContent();
                    content.setCatalog(text);//设置章节名
                    content.setCatalogContent(catalogContent.toString());//设置章节内容
                    content.setNovelName(bookName);//设置小说名
                    //将章节保存到数据库
                    novelAddService.saveCatalogMsg(catalog);
                    session.sendMessage(new TextMessage(text));//>>>>>>>>
                    //缓存小说章节信息
                    jedis.hset(KEY, bookName, text);

                    //将章节内容保存到数据库
                    novelAddService.saveCatalogContent(content);
                    //session.sendMessage(new TextMessage(JSON.toJSONString(content)));//>>>>>>>>
                    WebElement nextCatalog_A = webDriver.findElement(By.cssSelector("div.reader-main > div.read_nav > a#info_url"));
                    if(nextCatalog_A.getAttribute("href").contains("javascript")){
                        break;
                    }
                    nextCatalog_A.click();
                    log.debug(webDriver.getCurrentUrl());
                    Thread.sleep(1000);
                }
                //》》》获取章节信息结束《《《
            } else {//小说未被爬取
                webDriver.get(url);
                Thread.sleep(1000);
                //缓存小说信息
                jedis.hset(KEY, bookName, "");
                int counts = (Integer.parseInt(jedis.hget(KEY, "count")) + 1);
                jedis.hset(KEY, "count", counts + "");//小说数加一
                //获取小说信息开始
                WebElement authorAndState = webDriver.findElement(By.xpath("/html/body/div[1]/div[1]/div[2]/div/div[1]/span"));
                String authorAndStateText = authorAndState.getText();
                String author = authorAndState.findElement(By.tagName("a")).getText();
                String state = authorAndStateText.replace(author, "");
                author = author.replace("作 者：", "");
                state = state.replace(" 状态：", "");
                String lastUpdate = webDriver.findElement(By.xpath("/html/body/div[1]/div[1]/div[2]/div/div[2]/span")).getText().replace("最后更新：", "");
                String latestCatalogName = webDriver.findElement(By.xpath("/html/body/div[1]/div[1]/div[2]/div/div[2]/a")).getText().replace("最新章节：", "");
                String intro = webDriver.findElement(By.cssSelector("body > div:nth-child(3) > div.border3-2 > div.info-main > div > div.info-main-intro")).getText();
                String imgURL = webDriver.findElement(By.cssSelector(" div.info-main > img")).getAttribute("src");
                log.info("作者：" + author);
                log.info("状态：" + state);
                log.info("最后更新时间：" + lastUpdate);
                log.info("最后更新章节：" + latestCatalogName);
                log.info("简介：" + intro);
                log.info("类型：" + novelType);
                log.info("封面：" + imgURL);

                //保存图片

                URL bookImgURL = new URL(imgURL);
                InputStream in = bookImgURL.openStream();

                //2.在指定文件夹下创建文件。
                String path = PropertiesUtil.getValue("imgDir","D:/JavaFileBox/picture")  + File.separator + FileTypeUtil.imgNameEscape(bookName).replace("%", "_") + ".jpg";
                log.info("imgPath:" + path);
                File file = new File(path);
                if (!file.exists()) {
                    file.createNewFile();
                }
                //3.将下载保存到文件。
                FileOutputStream out = new FileOutputStream(file);
                Streams.copy(in, out, true);
                out.close();
                in.close();

                Novel novel = new Novel();
                novel.setBookIntro(intro);
                novel.setBookName(bookName);
                novel.setUpdateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(lastUpdate));
                novel.setBookAuthor(author);
                novel.setBookState(state);
                //保存小说和作者
                novelAddService.saveNovel1(novel);
                //保存小说类型
                novelAddService.saveNovelType(bookName, novelType);
                session.sendMessage(new TextMessage(JSON.toJSONString(novel)));//保存小说信息
                //》》》 获取小说信息开始结束《《《
                //》》》获取章节信息开始《《《
                int catalogNUM = webDriver.findElements(By.cssSelector("body > div.container.border3-2.mt8.mb20 > div.info-chapters.flex.flex-wrap > a")).size();
                for (int i = 0; i < catalogNUM; i++) {
                    WebElement e = webDriver.findElements(By.cssSelector("body > div.container.border3-2.mt8.mb20 > div.info-chapters.flex.flex-wrap > a")).get(i);
                    //String href = e.getAttribute("href");//章节链接
                    String text = e.getText();//章节名
                    //String currentUrl = webDriver.getCurrentUrl();
                    StringBuffer catalogContent = new StringBuffer("");
                    log.info("章节名：" + text);
                    e.click();//跳转到章节内容页面
                    Thread.sleep(1000);
                    Catalog catalog = new Catalog();//新建章节对象
                    catalog.setNovelName(bookName);
                    catalog.setNovelCatalog(text);
                    catalog.setVip(0);
                    catalog.setUpdateTime(new Date());
                    while (true) {
                        WebElement element = webDriver.findElement(By.cssSelector("#article"));
                        catalogContent.append(element.getText());
                        WebElement nextPage = webDriver.findElement(By.cssSelector("div.reader-main > div.read_nav > a#next_url"));
                        log.info("nextPage=" + nextPage.getText());
                        if (nextPage.getText().equals("下一页")) {
                            nextPage.click();
                            log.info("下一页URL：" + webDriver.getCurrentUrl());
                            Thread.sleep(1000);
                        } else {
                            break;
                        }
                    }
                    log.info("章节内容：" + catalogContent.toString().substring(0, 10));
                    CatalogContent content = new CatalogContent();
                    content.setCatalog(text);//设置章节名
                    content.setCatalogContent(catalogContent.toString());//设置章节内容
                    content.setNovelName(bookName);//设置小说名
                    //将章节保存到数据库
                    novelAddService.saveCatalogMsg(catalog);
                    session.sendMessage(new TextMessage(text));//>>>>>>>>
                    //缓存小说章节信息
                    jedis.hset(KEY, bookName, text);
                    //将章节内容保存到数据库
                    novelAddService.saveCatalogContent(content);
                    bookWords+=catalogContent.length();//更新数据库小说字数
                    novelAddService.updateWords(bookWords,bookName);
                    //session.sendMessage(new TextMessage(JSON.toJSONString(content)));//>>>>>>>>
//                    webDriver.findElement(By.cssSelector("div.reader-main > div.read_nav > a#info_url")).click();
                    WebElement nextCatalog_A = webDriver.findElement(By.cssSelector("div.reader-main > div.read_nav > a#info_url"));
                    if(nextCatalog_A.getAttribute("href").contains("javascript")){
                        break;
                    }
                    nextCatalog_A.click();
                    log.info(webDriver.getCurrentUrl());
                    Thread.sleep(1000);
                }
                //》》》获取章节信息结束《《《
            }

        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
        } finally {
            JedisUtil.close(jedis);
        }
        return flag;
    }

    @Override
    public List<String> getTyps() {
        List<String> list = new ArrayList<>();
        Jedis jedis = JedisUtil.getConnect();
        String key = "BQGTYPE";
        try {
            if (jedis.exists(key)) {
                String value = jedis.get(key);
                list = JSON.parseObject(value, List.class);
            } else {
                //开启webDriver进程
                WebDriver webDriver = initWebDriver();
                webDriver.get("https://www.ibiqiuge.com/");
                List<WebElement> aList = webDriver.findElements(By.xpath("/html/body/nav/a"));
                for (WebElement element : aList) {
                    String text = element.getText();
                    log.info("xpath" + text);
                    if ((!text.equals("首页")) && !text.equals("阅读记录")) {
                        list.add(text);
                    }
                }
                if (list.size() > 0) {
                    jedis.set(key, JSON.toJSONString(list));
                }
                webDriver.close();
                webDriver.quit();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JedisUtil.close(jedis);
        }
        log.info("list=" + list);
        return list;
    }
}
